package Features;

@ISA = qw(Exporter);
@EXPORT = qw();
@EXPORT_OK =  qw(%myvariable %cacheDicewd %cacheDicert %cacheDicewdnull %cacheDicertnull %cacheDict %cacheBasicEngHnd %cacheBasicHndEng 
		%cacheRootEngHnd %cacheRootHndEng %cacheMI %Dicewd %Dicert %Dicewdnull %Dicertnull %Dict %BasicEngHnd %BasicHndEng 
	        %RootEngHnd %RootHndEng %MI);

sub new {
	my($this) = {};
	bless $this;
	return $this;
}

sub valid_rel {
        my($prep) = shift;              
        my(@relations) = ("subj","obj","by","on","in","into","at","for","through","with","without","of","to","after","around","during","beneath","behind","from","adj","at","from","over","about","under","before","within","against","since","until","upon","among","despite","along","beyond","than","above","near","below","onto","inside","amongst","towards","besides");
        foreach $rel (@relations)
        {
                if($rel eq $prep)
                { return 1; }
        }
        return 0;
        
}            


sub get_windowdist {

	my($p,$q,$i);
	my($avgdist,$totelem);
	my($win,$window);

	for($win=2;$win<=4;$win++)
	{
		$window = $win;
		for($i=$window-1;$i<$nengwords;$i++)
		{
			$avgdist = 0;
			$totelem = 0;
			for($p=$i-2+1;$p<=$i;$p++)
			{
				for($q=$p+1;$q<=$i;$q++)
				{
					if($Align->{'aln'}->[$p] ne "-" && $Align->{'aln'}->[$q] ne "-")
					{
						$dist = abs($Align->{'aln'}->[$p] - $Align->{'aln'}->[$q]);
						$totelem ++;
					}
				}
			}

		}
		if($totelem)
		{  
			$this->{"windist_$window"} += $dist/$totelem; 
		}
	}
}

sub get_bigramdirectmag {

	my($this) = shift;
	my($Align) = shift;
	my($engsen) = shift;
	my($hinsen) = shift;
	my($conf) = shift;
	my($srcstr,$tgtstr);

	my($nengwords) = $#{$engsen->{'word'}}+1;
	my($nhinwords) = $#{$hinsen->{'word'}}+1;

	my($word1pos,$word1index,$word2pos,$word2index);
	my($word1,$word2);
	my($trunc1pos,$trunc2pos);
	my($dist,$distsrc);
	for($i=1;$i<$nengwords;$i++)
	{
		if($Align->{'aln'}->[$i] ne "-" && $Align->{'aln'}->[$i-1] ne "-")
		{
			$word2pos = $engsen->{'pos'}->[$i];
			$word2 = $engsen->{'wroot'}->[$i];
			$word2 = lc($word2);
			$word2pos =~/^(.)/g; $trunc2pos = $1;

			$word1pos = $engsen->{'pos'}->[$i-1];
			$word1 = $engsen->{'wroot'}->[$i-1];
			$word1 = lc($word1);
			$word1pos =~/^(.)/g; $trunc1pos = $1;

			$dist = $Align->{'aln'}->[$i] - $Align->{'aln'}->[$i-1];


			if($conf==1) {
				$srcstr = $word1.",".$word2;	
			}
			elsif($conf==2) {
				$srcstr = $word1pos.",".$word2pos;
			}
	
			if($dist==0)
			{
				$tgtstr = "XY";
			}
			elsif($dist<0)
			{
				$tgtstr = "Y<-X";
			}
			elsif($dist>0)
			{
				$tgtstr = "X->Y";
			}

			$this->{"$srcstr\_$tgtstr"}+= 1;
		}
	}
}

sub get_vargdist {
	my($this) = shift;
	my($Varg) = shift;
	my($Align) = shift;
	my($engsen) = shift;
	my($hinsen) = shift;
	my($conf) = shift;

        my($verbpos,$verbroot,$argroot,$argpos,$argcat,$argprep);
        my($verbtype,$truncpos,$mi,$dist);

        for($i=0;$i<=$#$Varg;$i++)
        {
                $verbpos = $Varg->[$i]->{'position'};
                $verbroot = $engsen->{'wroot'}->[$verbpos];

                for($j=0;$j<=$#{$Varg->[$i]->{'args'}};$j++)
                {
                        $argpos = $Varg->[$i]->{'args'}->[$j]->{'position'};
                        $argprep = $Varg->[$i]->{'args'}->[$j]->{'prep'};

                        $argroot = $engsen->{'wroot'}->[$argpos];
                        $argcat = $engsen->{'pos'}->[$argpos];
                        $argcat =~/^(.)/;
                        $truncpos = $1;

                        if($Align->{'aln'}->[$verbpos] ne "-" && $Align->{'aln'}->[$argpos] ne "-")
                        {
                                $dist = $Align->{'aln'}->[$verbpos] - $Align->{'aln'}->[$argpos];
                                $dist = &r(($dist+1)/$nhinwords,2);
                                $this->{"varg_$truncpos"} = $dist;
                        }
                }
        }

}

sub get_mergefeat {
	my($this) = shift;
	my($Varg) = shift;
	my($Align) = shift;
	my($engsen) = shift;
	my($hinsen) = shift;
	my($conf) = shift;
	my($nengwords) = $#{$engsen->{'word'}}+1;
	my($nhinwords) = $#{$hinsen->{'word'}}+1;

	my($verbpos,$verbroot,$argpos,$argroot,$argcat,$truncpos);

	# Computing the One verb compositionality feature
	my($verbtype,$truncpos,$mi);
	my($j);

	for($i=0;$i<=$#$Varg;$i++)
	{
		$verbpos = $Varg->[$i]->{'position'};
		$verbroot = $engsen->{'wroot'}->[$verbpos];
		for($j=0;$j<=$#{$Varg->[$i]->{'args'}};$j++)
		{
			$argpos = $Varg->[$i]->{'args'}->[$j]->{'position'};
			$argprep = $Varg->[$i]->{'args'}->[$j]->{'prep'};


			$argroot = $engsen->{'wroot'}->[$argpos];
			$argcat = $engsen->{'pos'}->[$argpos];
			$argcat =~/^(.)/;
			$truncpos = $1;

			# Merge based features

			if($Align->{'aln'}->[$verbpos] eq $Align->{'aln'}->[$argpos] || $Align->{'aln'}->[$verbpos] eq "-" || $Align->{'aln'}->[$argpos] eq "-")
			{

				$mi = 0; 

				$mi = $cacheMI{"$verbroot $argprep $argroot"};
				if(!$mi)
				{
					$mi = $MI{"$verbroot $argprep $argroot"};
					if($mi)
					{ $cacheMI{"$verbroot $argprep $argroot"} = $mi;  }
				}

				$mi = abs(int($mi + 0.5 * ($number <=> 0)));
			
				if($mi<3)
				{
					$this->{"merge_$truncpos\_LOW"} = 1;
				}
				elsif($mi<6)
				{
					$this->{"merge_$truncpos\_MED"} = 1;
				}
				else
				{
					$this->{"merge_$truncpos\_HIGH"} = 1;
				}
			}
		}
	}
}

sub get_depdirec {
	my($this) = shift;
	my($Dep) = shift;
	my($wordpos) = shift;
	my($Align) = shift;
	my($engsen) = shift;
	my($hinsen) = shift;
	my($conf) = shift;
	my($nengwords) = $#{$engsen->{'word'}}+1;
	my($nhinwords) = $#{$hinsen->{'word'}}+1;

	my($childPosition);
	my($t,$dist);
	my($parentPOS,$childPOS);
	my($parent,$child);
	my($wordaln,$childaln);

	my($srcstr,$tgtstr);

	my($GCONF) = $ENV{'GCONF'};

	$parentPOS = $engsen->{'pos'}->[$wordpos];
	$parent = lc($engsen->{'wroot'}->[$wordpos]);
	$wordaln = $Align->{'aln'}->[$wordpos];
	if($wordaln ne "-") {
		$tparentPOS = $hinsen->{'pos'}->[$wordaln];
	}
	$parentPOS=~/^(.)/; $truncparentPOS = $1;

	my($minaln,$maxaln);
	$maxaln = $wordaln;
	$minaln = $wordaln;

	my($GCONF) = $ENV{'GCONF'};

	for($t=0;$t<$Dep->[$wordpos]->{'noatt'};$t++)
	{
		$childPosition = $Dep->[$wordpos]->{'attch'}->[$t];
		$childPOS = $engsen->{'pos'}->[$childPosition];
		$child = lc($engsen->{'wroot'}->[$childPosition]);
		if($childaln ne "-") {
			$childaln = $Align->{'aln'}->[$childPosition];
		}
		$tchildPOS = $hinsen->{'pos'}->[$childaln];
		$childPOS=~/^(.)/; $truncchildPOS = $1;


		if($parentPOS ne "" && $childPOS ne "" && $wordaln ne "-" && $childaln ne "-")
		{
			if($conf==1) {
				if($wordpos>$childPosition) {
					$srcstr = $child."<-".$parent;	
				}
				else {
					$srcstr = $parent."->".$child;	
				}
			}
			if($conf==2) {
				if($wordpos>$childPosition) {
					$srcstr = $childPOS."<-".$parentPOS;	
				}
				else {
					$srcstr = $parentPOS."->".$childPOS;	
				}
			}
			elsif($conf==3) {
				$srcstr = $parent.",".$child;
			}	
			elsif($conf==4) {
				$srcstr = $parentPOS.",".$childPOS;
			}	

			$dist = $wordaln - $childaln;

			if($dist>0)
			{
				$tgtstr = "Y<-X";
			}
			elsif($dist<0)
			{
				$tgtstr = "X<-Y";
			}
			else
			{
				$tgtstr = "XY";
			}
		
			$this->{"$srcstr\_$tgtstr"}+=1;	
		}

		if($childaln ne "-" && $childaln<$minaln) { $minaln = $childaln; }
		elsif($childaln ne "-" && $childaln>$maxaln) { $maxaln = $childaln; }

		$this->get_depdirec($Dep,$childPosition,$Align,$engsen,$hinsen,$conf);
		
	}

	if($GCONF==11) {
		$this->{'avgspan'} += $maxaln - $minaln;
	}
}

sub getGFeatures {

	my($this) = shift;
	my($engsen) = shift;
	my($hinsen) = shift;
	my($Align) = shift;
	my($Varg) = shift;
	my($Dep) = shift;
	my($nengwords) = $#{$engsen->{'word'}}+1;
	my($nhinwords) = $#{$hinsen->{'word'}}+1;

        my($i,$j,$p);
        my($avvb_dist,$av,$tot,$overlap);

	my($GCONF) = $ENV{'GCONF'};

	# Get Overlap and Null
	my($overlap) = 0;
	my($total) = 0;
	my(%numberpos);
	my($nonnulls) = 0;

	for($i=0;$i<$nengwords;$i++)
	{
		if($Align->{'aln'}->[$i] ne "-")
		{
			$numberpos{$Align->{'aln'}->[$i]}++;
	#		print STDERR $i." ".$Align->{'aln'}->[$i]." ".$numberpos{$npos}."\n";
		}
	}

	foreach $npos (keys %numberpos)
	{
		if($numberpos{$npos}>1)
		{ $overlap+=$numberpos{$npos}*$numberpos{$npos}; }

		$nonnulls++;


		$total+= $numberpos{$npos};
	}

	if($GCONF==8 || $GCONF==10 || $GCONF==11) {
		if($total)
		{ $this->{'overlap'} = $overlap/$total; }
	}

	if($GCONF==11) {
		$this->{'nulls'} = ($nhinwords-$nonnulls)/$nhinwords;
	}

	my($rootpos,$roothinpos);

	if($GCONF==11) {
		$rootpos = $Dep->[0]->{'root'};
		if($Align->{'aln'}->[$rootpos])
		{ $this->{"rootpos"} = $Align->{'aln'}->[$rootpos]/$nhinwords; }
	}

	# avg span is computed in Dep direct, be careful
	if($GCONF==9 || $GCONF==10 || $GCONF==11) {
		$this->get_depdirec($Dep,$rootpos,$Align,$engsen,$hinsen,1);
	}

	if($GCONF==11) {
		$this->{'avgspan'}/=$nhinwords;
	}

	$this->get_mergefeat($Varg,$Align,$engsen,$hinsen,1);

	this->get_vargdist($Varg,$Align,$engsen,$hinsen);

	this->get_bigramdirecmag($Align,$engsen,$hinsen,1);

	this->get_windowdist($Align,$engsen,$hinsen);


}

sub getFeatures {
	my($this) = shift;
	my($engsen) = shift;
	my($hinsen) = shift;
	my($Align) = shift;
	my($Varg) = shift;
	my($Dep) = shift;
	my($nengwords) = $#{$engsen->{'word'}}+1;
	my($nhinwords) = $#{$hinsen->{'word'}}+1;

	my($FCONF) = $ENV{'FCONF'};

	my($i,$j,$p);	
	my($LFeatures);
	my($GFeatures);
	my($avvb_dist,$av,$tot,$overlap);

	for($i=0;$i<$nengwords;$i++)
	{
		$LFeatures = new Features;
		$LFeatures->getLFeatures($engsen,$hinsen,$i,$Align->{'aln'}->[$i]);
		$this->addFeatures($LFeatures);
	}


	#$GFeatures = new Features;
	#$GFeatures->getGFeatures($engsen,$hinsen,$Align,$Varg,$Dep);
#	$this->addFeatures($GFeatures);

}

sub get_srcposition {
	my($verbnum) = shift;
	my($argnum) = shift;
	my($Varg) = shift;
	my($j);
	my($num_between) = 1;

	if($Varg->[$verbnum]->{'args'}->[$argnum]->{'position'} < $Varg->[$verbnum]->{'position'})
	{
	for($j=0;$j<$Varg->[$verbnum]->{'Nargs'};$j++)
	{
		if($Varg->[$verbnum]->{'args'}->[$argnum]->{'position'} < $Varg->[$verbnum]->{'args'}->[$j]->{'position'} && $Varg->[$verbnum]->{'args'}->[$j]->{'position'} < $Varg->[$verbnum]->{'position'})
		{
			$num_between++;
		}
		return -1*$num_between;
	}
	}
	elsif($Varg->[$verbnum]->{'args'}->[$argnum]->{'position'} > $Varg->[$verbnum]->{'position'})
	{
	for($j=0;$j<$Varg->[$verbnum]->{'Nargs'};$j++)
	{
		if($Varg->[$verbnum]->{'args'}->[$argnum]->{'position'} > $Varg->[$verbnum]->{'args'}->[$j]->{'position'} && $Varg->[$verbnum]->{'args'}->[$j]->{'position'} > $Varg->[$verbnum]->{'position'})
		{
			$num_between++;
		}
		return $num_between;
	}
	}
}

sub addFeatures {
	my($this) = shift;
	my($Feats) = shift;
	foreach $Feat (keys %{$Feats})
	{
		$this->{$Feat} += $Feats->{$Feat};
	}
}

sub getLFeatures {
	my($this) = shift;
	my($engsen) = shift;
	my($hinsen) = shift;
	my($sword)= shift;
	my($tword) = shift;

	my($FCONF) = $ENV{'FCONF'};

	my($srcword,$srccat,$srcroot,$srcrole,$verbroot);

	$srcword = $engsen->{'word'}->[$sword];			
	$srcroot = $engsen->{'wroot'}->[$sword];			
	$srcroot = lc($srcroot);
	$srccat = $engsen->{'pos'}->[$sword];			

	if($tword eq "-")
	{
		my($srcrole);

	#	if($FCONF == 2 || $FCONF == 7) {
	#		$this->{"null_$srccat"} = 1; 
	#	}

		if($FCONF == 4 || $FCONF==5 || $FCONF==6 || $FCONF==7 || $FCONF==8) {
			$srccat=~/^(.)/g;
			$this->{"null_$1"} = 1;
		}

		$tgtword = "null";
		$tgtcat = "null";
		$tgtroot = "null";

		#return;
	}
	else
	{
		$tgtword = $hinsen->{'word'}->[$tword];			
		$tgtroot = $hinsen->{'wroot'}->[$tword];			
		$tgtcat = $hinsen->{'pos'}->[$tword];	

	}

	my($DiceWord,$DiceRoot,$DiceWordnull,$DiceRootnull,$Dictionary);

	$DiceWord = $cacheDicewd{"$srcword $tgtword"};
	if(!($DiceWord))
	{ 
		$DiceWord = $Dicewd{"$srcword $tgtword"};
		if($DiceWord)
		{ $cacheDicewd{"$srcword $tgtword"} = $DiceWord; }
	}
	if($tgtword eq "null")
	{

		$DiceWordnull = $cacheDicewdnull{"$srcword null"};
		if(!$DiceWordnull)
		{
			$DiceWordnull = $Dicewdnull{"$srcword null"};
			if($DiceWordnull)
			{ $cacheDicewdnull{"$srcword null"} = $DiceWordnull; }
		}
	}

	$DiceRoot = $cacheDicert{"$srcroot $tgtroot"};
	if(!($DiceRoot))
	{ 
		$DiceRoot = $Dicewd{"$srcroot $tgtroot"};
		if($DiceRoot)
		{ $cacheDicert{"$srcroot $tgtroot"} = $DiceRoot; }
	}
	if($tgtroot eq "null")
	{
		$DiceRootnull = $cacheDicertnull{"$srcroot null"};
		if(!$DiceRootnull)
		{
			$DiceRootnull = $Dicertnull{"$srcroot null"};
			if($DiceRootnull)
			{ $cacheDicertnull{"$srcroot null"} = $DiceRootnull; }
		}
	}

	$Dictionary = $cacheDict{"$srcroot $tgtroot"};
	if(!($Dictionary))
	{
		$Dictionary = $Dict{"$srcroot $tgtroot"};
		if($Dictionary)
		{ $cacheDict{"$srcroot $tgtroot"} = $Dictionary; }
	}

	$basic_eng_hnd = $cacheBasicEngHnd{"$srcword $tgtword"};
	if(!($basic_eng_hnd))
	{
		$basic_eng_hnd = $BasicEngHnd{"$srcword $tgtword"};
		if($basic_eng_hnd)
		{ $cacheBasicEngHnd{"$srcword $tgtword"} = $basic_eng_hnd; }
	}

	$basic_hnd_eng = $cacheBasicHndEng{"$srcword $tgtword"};
	if(!($basic_hnd_eng))
	{
		$basic_hnd_eng = $BasicHndEng{"$srcword $tgtword"};
		if($basic_hnd_eng)
		{ $cacheBasicHndEng{"$srcword $tgtword"} = $basic_hnd_eng; }
	}

	$root_eng_hnd = $cacheRootEngHnd{"$srcroot $tgtroot"};
	if(!($root_eng_hnd))
	{
		$root_eng_hnd = $RootEngHnd{"$srcroot $tgtroot"};
		if($root_eng_hnd)
		{ $cacheRootEngHnd{"$srcroot $tgtroot"} = $root_eng_hnd; }
	}

	$root_hnd_eng = $cacheRootHndEng{"$srcroot $tgtroot"};
	if(!($root_hnd_eng))
	{
		$root_hnd_eng = $RootHndEng{"$srcroot $tgtroot"};
		if($root_hnd_eng)
		{ $cacheRootHndEng{"$srcroot $tgtroot"} = $root_hnd_eng; }
	}

	if($DiceWord) { 
		if($FCONF != 2) {
			$this->{'diceword'} = $DiceWord; 
		}
	}
	elsif($DiceWordnull) { 
		if($FCONF != 2) {
			$this->{'diceword'} = $DiceWordnull; 
		}
		if($FCONF==1 || $FCONF==3) {
			$this->{'dicewordnull'} = $DiceWordnull; 
		}
	}
	#elsif($tgtword eq "null")
	#{ $this->{'diceword'} = 2/50000; }

	if($DiceRoot) { 
		if($FCONF != 1) {
			$this->{'diceroot'} = $DiceRoot; 
		}
	}
	elsif($DiceRootnull) { 
		if($FCONF != 1) {
			$this->{'diceroot'} = $DiceRootnull; 
		}
		if($FCONF==2 || $FCONF==3) {
			$this->{'dicerootnull'} = $DiceRootnull; 
		}
	}
	#elsif($tgtroot eq "null")
	#{ $this->{'diceroot'} = 2/50000; }

	#if($DiceWord && $DiceRoot) { $this->{'diceprod'} = sqrt($DiceWord*$DiceRoot); }

	if($Dictionary) { 
		if($FCONF==5 || $FCONF==6 || $FCONF==7 || $FCONF==8 ) {
			$this->{'dictionary'} = $Dictionary; 
		}
	}

	if($FCONF==6) {
		$this->{"rt_$srcroot\_$tgtroot"} = 1;
	}


	#if($basic_eng_hnd) { $this->{'basic_eng_hnd'} = $basic_eng_hnd; }
	#if($basic_hnd_eng) { $this->{'basic_hnd_eng'} = $basic_hnd_eng; }
	#if($root_eng_hnd) { $this->{'root_eng_hnd'} = $root_eng_hnd; }
	#if($root_hnd_eng) { $this->{'root_hnd_eng'} = $root_hnd_eng; }

	# Distance Feature
	my($dist);
	if($tword ne "-")
	{
	#	$dist = abs($sword/($#{$engsen->{'word'}}+1) - $tword/($#{$hinsen->{'word'}}+1));
	#	$this->{'dist'} = $dist;

	#	my($totalequal,$consequal,$fracoverlap);
	#	$totalequal = &ifequal($srcword,$tgtword);
	#	if($totalequal) { $this->{'equal'} = 1; }
	#	$consequal = &ifconsequal($srcword,$tgtword);
	#	if($consequal) { $this->{'consequal'} = 1; }

		if($FCONF==7 || $FCONF==8) {
			$fracoverlap = &fracoverlap($srcword,$tgtword);
			if($fracoverlap) { $this->{'fracoverlap'} = 1; }
		}

	}

}

sub ifequal {
	
	my($srcword) = lc($_[0]);
	my($tgtword) = lc($_[1]);

	if($srcword eq $tgtword)
	{
		return 1;
	}
	return 0;
}

sub ifconsequal {

	my($srcword) = lc($_[0]);
	my($tgtword) = lc($_[1]);

	$srcword=~s/[aeiou,;\.\:\-\\\/\"\'\*\%\$]+//g;
	$tgtword=~s/[aeiou,;\.\:\-\\\/\"\'\*\%\$]+//g;

	if($srcword eq $tgtword)
	{
		return 1;
	}
	return 0;
}

sub fracoverlap {

        my($srcword) = $_[0];
        my($tgtword) = $_[1];

	if($srcword=~/^[^A-Z]/)
	{
		return 0;
	}


        $tgtword=~s/[\$\%\&\*\?\+\(\)\[\]\\\.]+//g;
        $tgtword=lc($tgtword);

        $tgtword=~s/[aeiou]//g;

        $tgtword=~s/w/t/g;
        $tgtword=~s/x/d/g;
        $tgtword=~s/k/c/g;
        $tgtword=~s/([a-z])m/$1n/g;
        $tgtword=~s/z/j/g;
        $tgtword=~s/p/f/g;

        $srcword=~s/[\$\%\&\*\?\+\(\)\[\]\\]//g;
        $srcword=lc($srcword);
        $srcword=~s/[aeiou]//g;
        $srcword=~s/([a-z])m/$1n/g;
        $srcword=~s/z/j/g;


        my ($longest_c, $longest,$strlen,$substr) = 0;
         for my $start (0..length $tgtword) {
            for my $len ( reverse $start+1 .. length $tgtword) {
            my $substr = substr($tgtword, $start, $len);

                while($srcword =~/($substr)/g)
                {
                        $substr = $1;
                        $strlen = length $1;
                        if($strlen > $longest_c)
                        { ($longest_c, $longest) = ($strlen, $substr); }
                }
            }
         }

        if(length($srcword)==0) { return 0; }
        return (length($longest)/(length($srcword)));
}


sub verbtype {
	my($verbroot) = shift;
	if($verbroot eq "take" || $verbroot eq "be" || $verbroot eq "make")
	{ return $verbroot; }
	return;
}

sub auxtype {
	my($root) = shift;
	my($cat) = shift;

	if($cat eq "v" && ( $root eq "WA" || $root eq "kara" || $root eq "jA" || $root  eq "raha" || $root eq "banA" || $root eq "ho" || $root eq "hE" || $root eq "jAna" || $root eq "le" || $root eq "ho" || $root eq "uTA" || $root eq "xe" ))
	{ return $root; }
	return;
}

sub preptype {
	my($root) = shift;
	my($cat) = shift;
	if($cat eq "p")
	{ return $root; }
	return 0;
}

sub dotProduct {
	my($Features1) = shift;
	my($Features2) = shift;
	my($dotproduct) = 0;
	foreach $feature (keys %{$Features1})
	{
		$dotproduct += $Features1->{$feature}*$Features2->{$feature};
	}
	return $dotproduct;
}

sub difffeatures {
	my($this) = shift;
	my($Features1) = shift;
	my($Features2) = shift;

	foreach $feature (keys %{$Features1})
	{
		$this->{$feature} = $Features1->{$feature};
	}

	foreach $feature (keys %{$Features2})
	{
		$this->{$feature} -= $Features2->{$feature};
	}
}

sub difffeatures2 {
	my($this) = shift;
	my($Features1) = shift;
	my($Features2) = shift;

	foreach $feature (keys %{$Features2})
	{
		$this->{$feature} = $Features1->{$feature} - $Features2->{$feature};
	}

}

sub r {
    my ($number,$decimals) = @_;
    return substr($number+("0."."0"x$decimals."5"),
                  0, $decimals+length(int($number))+1);
}

1;
